package server;

import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * @author Elvis
 * @version 1.0, 2024-02-28
 */
public class HttpConnector implements Runnable {

    public static Map<String, HttpSession> sessions = new HashMap<>();
    private final int minProcessor = 2;
    private final int maxProcessor = 10;
    private int curProcessor = 0;

    private int threadNum = 0;
    private int processorNum = 0;

    private final Deque<HttpProcessor> processorQueue = new ArrayDeque<>(maxProcessor);

    public static HttpSession createSession() {
        Session session = new Session();
        session.setValid(true);
        session.setCreationTime(System.currentTimeMillis());
        String sessionId = generateSessionId();
        session.setId(sessionId);
        sessions.put(sessionId, session);
        return session;
    }

    // 以随机方式生成byte数组,形成sessionid
    protected static synchronized String generateSessionId() {
        Random random = new Random();
        long seed = System.currentTimeMillis();
        random.setSeed(seed);
        byte bytes[] = new byte[16];
        random.nextBytes(bytes);
        StringBuffer result = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            byte b1 = (byte) ((bytes[i] & 0xf0) >> 4);
            byte b2 = (byte) (bytes[i] & 0x0f);
            if (b1 < 10) result.append((char) ('0' + b1));
            else result.append((char) ('A' + (b1 - 10)));
            if (b2 < 10) result.append((char) ('0' + b2));
            else result.append((char) ('A' + (b2 - 10)));
        }
        return (result.toString());
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "----" + "HttpConnector start...");
        initProcessor();
        try {
            ServerSocket serverSocket = new ServerSocket(8088, 1, InetAddress.getByName("127.0.0.1"));
            while (true) {
                // System.out.println(Thread.currentThread().getName() + "----" + "Waiting for connection...");
                Socket accept = serverSocket.accept();
                if (accept == null) {
                    continue;
                }
                HttpProcessor processor = createProcessor();
                if (processor == null) {
                    System.out.println(Thread.currentThread().getName() + "----" + "HttpProcessor queue is full");
                    accept.close();
                    continue;
                }
                processor.assign(accept);
                System.out.println(Thread.currentThread().getName() + "----" + "Accept a connection");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建一个HttpProcessor
     *
     * @return
     */
    private HttpProcessor createProcessor() {
        synchronized (processorQueue) {
            // 不为空
            if (!processorQueue.isEmpty()) {
                System.out.println(Thread.currentThread().getName() + "----" + "HttpProcessor queue size: " + processorQueue.size());
                HttpProcessor pop = processorQueue.pop();
                return pop;
            }

            if (curProcessor < maxProcessor) {
                HttpProcessor processor = new HttpProcessor(this);
                processor.start(processorNum++);
                curProcessor++;
                return processor;
                // processorQueue.add(processor);
            }
            return null;
            // while (processorQueue.isEmpty()) {
            //     if (curProcessor < maxProcessor) {
            //         HttpProcessor processor = new HttpProcessor(this);
            //         processor.start(processorNum++);
            //         curProcessor++;
            //         // processorQueue.add(processor);
            //     } else {
            //         try {
            //             super.wait();
            //         } catch (InterruptedException e) {
            //             throw new RuntimeException(e);
            //         }
            //     }
            // }
            // HttpProcessor pop = processorQueue.pop();
            // return pop;
        }
    }

    /**
     * 回收processor
     */
    public void recycleProcessor(HttpProcessor processor) {
        if (processor != null) {
            // System.out.println(Thread.currentThread().getName() + "----" + "HttpProcessor queue size before recycle:  " + processorQueue.size());
            processorQueue.add(processor);
            System.out.println(Thread.currentThread().getName() + "----" + "HttpProcessor queue size after recycle:  " + processorQueue.size());
        }
    }

    private void initProcessor() {
        // System.out.println(Thread.currentThread().getName() + "----" + "HttpProcessor queue size initing:  ");
        for (int i = 0; i < minProcessor; i++) {
            HttpProcessor processor = new HttpProcessor(this);
            processorQueue.add(processor);
            processor.start(processorNum++);
        }
        curProcessor = minProcessor;
        System.out.println(Thread.currentThread().getName() + "----" + "HttpProcessor queue size after init:  " + processorQueue.size());

    }

    public void start() {
        Thread thread = new Thread(this, "HttpConnector " + threadNum++);
        thread.start();
    }
}
